<!--
 * @Author: Wangtao
 * @Date: 2020-09-21 09:55:09
 * @LastEditors: Wangtao
 * @LastEditTime: 2021-01-27 14:21:10
-->
<template>
  <div
    class="workflow"
    ref="workflow"
    v-loading="loading"
    element-loading-text="初始化数据...">
    <div class="drag-box border" id="drag">
      <node-menu @addNode="addNode" ref="nodeMenu"></node-menu>
      <canvas-operation
        @pageBack="pageBack"
        @scale="zoomScale"
        @enlarge="enlargeCanvas"
        @save="ivrSaveClick"
        :data="ivrData">
      </canvas-operation>

      <!-- 主要画布 -->
      <section
        class="drop"
        @contextmenu="canvasRightClick"
        ref="mainContainer"
        @keyup.delete="keyBoardClick">
        <div id="canvas" class="canvas" ref="efContainer" :style="canvasStyle">
          <template v-for="node in data.nodeList">
            <flow-node
              :id="node.id"
              :key="node.id"
              :node="node"
              :activeElement="activeElement"
              @changeNodeSite="changeNodeSite"
              @dbClick="dbClickNode"
              @nodeClick="nodeClick"
              @delete="deleteNode">
            </flow-node>
          </template>
        </div>
      </section>
    </div>
    <!-- 右侧节点配置 -->
    <el-drawer
      custom-class="m7-drawer"
      :title="currentNode.type | filterEditName"
      :visible.sync="isShowDrawer"
      :append-to-body="true"
      :size="'40%'"
      direction="rtl"
      ref="drawer"
      class="im-edit-drawer">
      <component
        v-if="isShowDrawer"
        :is="currentNode.type"
        :ref="currentNode.id"
        :data="data"
        :currentNode="currentNode"
        @save="nodeEditSave"
        @cancel="nodeEditCancel"
        @delete="deleteNode"
      ></component>
    </el-drawer>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Mixins } from 'vue-property-decorator'

import { jsPlumb } from 'jsplumb'

import panzoom from 'panzoom'

import nodeMenu from './node_menu.vue'
import canvasOperation from './canvas_operation.vue'

import jsPlumbMixin from './mixins'

import FlowNode from './node.vue'
import cloneDeep from 'lodash/cloneDeep'
import merge from 'lodash/merge'
import { v4 as uuidv4 } from 'uuid'

// 节点配置
import imNodeStart from '../nodeEdit/startNode.vue'
import imNodeDate from '../nodeEdit/im-node-date.vue'
import imNodeTransfer from '../nodeEdit/im-node-transfer.vue'
import imNodeMenu from '../nodeEdit/im-node-menu.vue'
import imNodeLeave from '../nodeEdit/im-node-leave.vue'

import imNodeRobot from '../nodeEdit/im-node-robot.vue'
import imNodeBranch from '../nodeEdit/im-node-branch.vue'
import { IvrModule } from '@/store/modules/config/ivr'

import { IvrData, LineListObj, NodeConditionObj, NodeDataObj, NodeObj } from '../types/index'

// 节点默认配置
import defaultNode from './nodeDefault'
import { ComputedOptions } from 'vue'
@Component({
  name: 'FlowChart',
  components: {
    nodeMenu,
    FlowNode,
    canvasOperation,
    imNodeStart,
    imNodeDate,
    imNodeMenu,
    imNodeLeave,
    imNodeTransfer,
    imNodeRobot,
    imNodeBranch
  },
  directives: {},
  filters: {
    filterEditName (type) {
      let title = '编辑'
      if (type === 'im-node-start') {
        title += '开始节点'
      } else if (type === 'im-node-play') {
        title += '播放语音节点'
      } else if (type === 'im-node-date') {
        title += '时间条件节点'
      } else if (type === 'im-node-transfer') {
        title += '转人工节点'
      } else if (type === 'im-node-menu') {
        title += '引导菜单节点'
      } else if (type === 'im-node-leave') {
        title += '留言节点'
      } else if (type === 'im-node-robot') {
        title += '机器人节点'
      } else if (type === 'im-node-branch') {
        title += '分支路由节点'
      }
      return title
    }
  }
})

export default class FlowChart extends Mixins(jsPlumbMixin) {
  @Prop({ default: {} }) private ivrData: IvrData | undefined

  private savedNodeList: string[] = []

  private loading: boolean = false

  private data: IvrData = {
    nodeList: []
  }

  private nodeForm = {
    // 右侧抽屉form
    nodeId: '',
    nodeName: '',
    desc: ''
  }

  private activeElement: any = {
    type: '',
    sourceId: '',
    targetId: ''
  }

  private dragInstance: any = ''
  private dropInstance: any = '' // jsplumb 在右侧画布的实例
  private nodes: any = []
  private currentNode: any = {}
  private deleteTarget: any = {
    type: '',
    nodeId: '', // 删除节点需要
    connection: '' // 删除连线需要
  }

  private isShowDrawer: any = false // 右侧抽屉
  private contextMenuPosition = [-100, -100]
  private zoom = 1
  private mainContainerWrap: any = ''
  private pan: any = ''
  private flowInfo = {}
  private $message: any
  private jsPlumb: any

  private canvasStyle: any = {
    width: '',
    height: '',
    left: '',
    top: '',
    transformOrigin: '50%'
  }

  private getTransform: any = {}

  private setCanvasSize () {
    const elFlow = window.getComputedStyle((this.$refs as any).workflow)
    const width = parseFloat(elFlow.width.replace('px', ''))
    const height = parseFloat(elFlow.height.replace('px', ''))
    // 画布大小
    const setwidth = 40000
    const setheight = 20000
    const setleft = (setwidth / 2 - width / 2) * -1
    const settop = (setheight / 2 - height / 2) * -1
    this.canvasStyle = {
      width: setwidth + 'px',
      height: setheight + 'px',
      left: setleft + 'px',
      top: settop + 'px',
      transformOrigin: '50%'
    }
  }

  private zoomCanvas () {
    const mainContainer = (this.$refs as any).efContainer
    const mainContainerWrap = (this.$refs as any).mainContainer
    const el = window.getComputedStyle(mainContainerWrap)
    const swidth = 40000 / parseFloat(el.width.replace('px', '')) * 0.5
    const sheight = 20000 / parseFloat(el.height.replace('px', '')) * 0.5
    const pan = panzoom(mainContainer, {
      smoothScroll: false,
      bounds: false,
      zoomDoubleClickSpeed: 1,
      minZoom: 0.3,
      maxZoom: 1,
      zoomSpeed: 0.1,
      initialX: 0,
      initialY: 0,
      transformOrigin: { x: swidth, y: sheight }
    })
    this.mainContainerWrap = mainContainerWrap
    this.pan = pan
    // 缩放时设置jsPlumb的缩放比率
    pan.on('zoomend', (e: any) => {
      const { scale } = e.getTransform()
      // const elFlow: any = window.getComputedStyle((this.$refs as any).efContainer)
      // const width = elFlow.width / 2 / scale * -1
      // const height = elFlow.height / 2 / scale * -1
      this.getTransform = e.getTransform()
      this.jsPlumb.setZoom(scale)
    })

    pan.on('panend', (e: any) => {
      // this.getTransform = e.getTransform()
    })

    // 平移时设置鼠标样式
    mainContainer.style.cursor = 'grabbing'
    // mainContainer.addEventListener('mousedown', () => {
    //   (this as any).style.cursor = 'grabbing'
    //   mainContainer.addEventListener('mouseout', () => {
    //     (this as any).style.cursor = 'default'
    //   })
    // })
    // mainContainer.addEventListener('mouseup', () => {
    //   (this as any).style.cursor = 'default'
    // })
  }

  private pageBack () {
    this.$emit('pageBack')
  }

  private created () {
    if (!IvrModule.cacheSign) {
      this.loading = true
      IvrModule.getNodeCache().then(() => {
        this.loading = false
      })
    }
  }

  private mounted (): void {
    this.setCanvasSize()
    this.$nextTick(() => {
      // 默认加载流程的数据、在这里可以根据具体的业务返回符合流程数据格式的数据即可
      const elFlow = window.getComputedStyle((this.$refs as any).efContainer)
      const left: number = parseFloat(elFlow.width.replace('px', '')) / 2 - 80
      const top: number = parseFloat(elFlow.height.replace('px', '')) / 2 - 200
      let getDataB: IvrData | undefined
      if (this.ivrData && this.ivrData.nodeList && this.ivrData.nodeList.length > 0) {
        getDataB = this.ivrData
      } else {
        getDataB = {
          name: '',
          nodeList: [
            {
              id: 'startNode',
              type: 'im-node-start',
              left: left + 'px',
              top: top + 'px',
              viewOnly: true,
              name: '开始节点',
              condition: [{ label: '下一步' }],
              data: this.getDefaultNode('im-node-start')
            }
          ],
          lineList: []
        }
      }
      this.dataReload(getDataB)
    })
  }

  /**
   * @description 获取缩放比率
   * @returns {number} 缩放比率
   */
  private getScale () {
    let scale1
    const { pan, dropInstance } = this
    if (pan) {
      const { scale } = pan.getTransform()
      scale1 = scale
    } else {
      const matrix = window.getComputedStyle(dropInstance.getContainer()).transform
      scale1 = (matrix as any).split(', ')[3] * 1
    }
    dropInstance.setZoom(scale1)
    return scale1
  }

  /**
   * @description: 屏蔽浏览器右键点击事件
   * @param {type}
   * @return:
   */
  private canvasRightClick (event) {
    event.preventDefault()
    event.stopPropagation()
    return false
  }

  private zoomScale (type: string) {
    const { pan } = this
    const mainContainer = (this.$refs as any).efContainer
    const x = mainContainer.clientWidth / 2
    const y = mainContainer.clientHeight / 2
    if (type === 'out') {
      pan.smoothZoom(x, y, 1.5)
    } else if (type === 'in') {
      pan.smoothZoom(x, y, 0.5)
    } else {
      pan.smoothZoom(0, 0, 100)
      pan.moveTo(0, 0)
    }
  }

  // 平移缩放操作
  private enlargeCanvas (elarge: string) {
    const position = elarge ? 'fixed' : 'absolute';
    (this.$refs as any).workflow.parentNode.style.position = position
    this.$nextTick(() => {
      this.setCanvasSize()
      this.zoomCanvas()
    })
  }

  private addNode (evt, Menu, mousePosition) {
    const screenX = evt.originalEvent.clientX
    const screenY = evt.originalEvent.clientY
    const efContainer = (this.$refs as any).efContainer
    const matrix = window.getComputedStyle(efContainer).transform
    const scale1 = (matrix as any).split(', ')[3] * 1
    const containerRect = efContainer.getBoundingClientRect()
    let left = screenX
    let top = screenY
    // 计算是否拖入到容器中
    if (left < containerRect.x || left > containerRect.width + containerRect.x || top < containerRect.y || containerRect.y > containerRect.y + containerRect.height) {
      (this.$message as any).error('请把节点拖入到画布中')
      return
    }
    left = left - containerRect.x + efContainer.scrollLeft
    top = top - containerRect.y + efContainer.scrollTop
    // 居中
    left -= 85
    top -= 16
    left = left / scale1
    top = top / scale1
    const nodeId = this.getUUID()
    // 动态生成名字
    const origName = Menu.name
    const nodeName = origName
    const nodeLabel = this.getDefaultConditionLabel(Menu.type)
    const node = {
      id: nodeId,
      name: nodeName,
      type: Menu.type,
      left: left + 'px',
      top: top + 'px',
      ico: Menu.ico,
      condition: this.getDefaultConditionList(Menu.type, nodeId, nodeLabel),
      data: this.getDefaultNode(Menu.type)
    };
    /**
     * 这里可以进行业务判断、是否能够添加该节点
     */
    (this.data.nodeList as NodeObj[]).push(node)
    this.savedNodeList.push(nodeId)
    this.$nextTick(() => {
      for (let h = 0; h < node.condition.length; h++) {
        this.jsPlumb.makeSource(nodeId + '-' + h, this.jsplumbSourceOptions)
      }
      this.jsPlumb.makeTarget(nodeId, this.jsplumbTargetOptions)
      this.jsPlumb.draggable(nodeId, {
        containment: 'parent',
        stop (el) {
          // 拖拽节点结束后的对调
          console.log('拖拽结束: ', el)
        }
      })
    })
  }

  // 获取节点默认信息
  private getDefaultNode (type: string): NodeDataObj {
    return defaultNode[type]
  }

  // 加载流程图
  private dataReload (data) {
    this.easyFlowVisible = false;
    (this.data.nodeList as NodeObj[]) = [];
    (this.data.lineList as LineListObj[]) = []
    this.$nextTick(() => {
      this.easyFlowVisible = true
      this.data = cloneDeep(data)
      this.$nextTick(() => {
        this.jsPlumb = jsPlumb.getInstance()
        this.$nextTick(() => {
          this.jsPlumbInit()
        })
      })
    })
  }

  private jsPlumbInit () {
    this.jsPlumb.ready(() => {
      // 导入默认配置
      this.jsPlumb.importDefaults(this.jsplumbSetting)
      this.zoomCanvas()
      // 会使整个jsPlumb立即重绘。
      this.jsPlumb.setSuspendDrawing(false, true)
      // 初始化节点
      this.loadEasyFlow()
      // 单点击了连接线, https://www.cnblogs.com/ysx215/p/7615677.html
      this.jsPlumb.bind('click', (conn, originalEvent) => {
        this.activeElement.type = 'line'
        this.activeElement.sourceId = conn.sourceId
        this.activeElement.targetId = conn.targetId
        const line = this.jsPlumb.getConnections({
          source: conn.sourceId,
          target: conn.targetId
        })[0]
        this.jsPlumb.deleteConnection(line)
        const connParam = {
          source: conn.sourceId,
          target: conn.targetId
          // paintStyle: {
          //   // stroke: 'red',
          //   strokeWidth: 3,
          //   // 设置外边线的颜色，默认设置透明，这样别人就看不见了，点击线的时候可以不用精确点击，参考 https://blog.csdn.net/roymno2/article/details/72717101
          //   outlineStroke: 'transparent',
          //   // 线外边的宽，值越大，线的点击范围越大
          //   outlineWidth: 10
          // },
          // hoverPaintStyle: { stroke: 'red', strokeWidth: 3 }
        }
        this.jsPlumb.connect(connParam, this.jsplumbConnectOptions)
      })
      // 连线
      this.jsPlumb.bind('connection', (evt) => {
        const from = evt.source.id
        const to = evt.target.id
        if (this.loadEasyFlowFinish) {
          (this.data.lineList as LineListObj[]).push({ from, to })
        }
      })

      // 删除连线回调
      this.jsPlumb.bind('connectionDetached', (evt) => {
        this.deleteLine(evt.sourceId, evt.targetId)
      })

      // 改变线的连接节点
      this.jsPlumb.bind('connectionMoved', (evt) => {
        this.changeLine(evt.originalSourceId, evt.originalTargetId)
      })

      // 连线右击
      this.jsPlumb.bind('contextmenu', (evt) => {
        console.log('contextmenu', evt)
      })

      // 连线
      this.jsPlumb.bind('beforeDrop', (evt) => {
        const from = evt.sourceId
        const to = evt.targetId
        if (from.split('-')[0] === to) {
          return false
        }
        if (to === 'startNode') {
          this.$message.error('开始节点不支持连接')
          return false
        }
        if (this.hasLineFrom(from)) {
          this.$message.error('条件无法与多个节点关联')
          return false
        }
        if (to.indexOf(from) > -1) {
          this.$message.error('节点不支持连接自己')
          return false
        }
        if (from === to) {
          this.$message.error('节点不支持连接自己')
          return false
        }
        if (this.hasLine(from, to)) {
          this.$message.error('该关系已存在,不允许重复创建')
          return false
        }
        if (this.hashOppositeLine(from, to)) {
          this.$message.error('不支持两个节点之间连线回环');
          return false
        }
        this.$message.success('连接成功')
        const connParam = {
          source: from,
          target: to,
          paintStyle: {
            // 线的颜色
            stroke: '#8D9DB0',
            // 线的粗细，值越大线越粗
            strokeWidth: 3,
            // 设置外边线的颜色，默认设置透明，这样别人就看不见了，点击线的时候可以不用精确点击，参考 https://blog.csdn.net/roymno2/article/details/72717101
            outlineStroke: 'transparent',
            // 线外边的宽，值越大，线的点击范围越大
            outlineWidth: 3
          }
        }
        this.jsPlumb.connect(connParam, this.jsplumbConnectOptions)
        return false
      })

      // beforeDetach
      this.jsPlumb.bind('beforeDetach', (evt) => {
        console.log('beforeDetach', evt)
      })
      this.jsPlumb.setContainer(this.$refs.efContainer)
    })
  }

  // 加载流程图
  private loadEasyFlow () {
    // 初始化节点
    for (let i = 0; i < (this.data.nodeList as NodeObj[]).length; i++) {
      const node = (this.data.nodeList as NodeObj[])[i]
      // 设置源点，可以拖出线连接其他节点
      if (!this.isSingleOutletNode(node.type)) {
        for (let h = 0; h < (node.condition as NodeConditionObj[]).length; h++) {
          this.jsPlumb.makeSource(node.id + '-' + h, merge(this.jsplumbSourceOptions, {}))
        }
      } else {
        this.jsPlumb.makeSource(node.id, merge(this.jsplumbSourceOptions, {}))
      }
      // // 设置目标点，其他源点拖出的线可以连接该节点
      this.jsPlumb.makeTarget(node.id, this.jsplumbTargetOptions)
      if (!node.viewOnly) {
        this.jsPlumb.draggable(node.id, {
          containment: 'parent',
          stop (el) {
            // 拖拽节点结束后的对调
            console.log('拖拽结束: ', el)
          }
        })
      }
    }
    this.$nextTick(() => {
      for (let g = 0; g < (this.data.lineList as LineListObj[]).length; g++) {
        const line = (this.data.lineList as LineListObj[])[g]
        const connParam = {
          source: line.from,
          target: line.to,
          label: line.label ? line.label : '',
          connector: line.connector ? line.connector : '',
          anchors: line.anchors ? line.anchors : undefined,
          paintStyle: line.paintStyle ? line.paintStyle : undefined
        }
        this.jsPlumb.connect(connParam, this.jsplumbConnectOptions)
      }
    })
    // 初始化连线
    this.$nextTick(function () {
      this.loadEasyFlowFinish = true
    })
  }

  // 改变节点的位置
  private changeNodeSite (data) {
    for (let i = 0; i < (this.data.nodeList as NodeObj[]).length; i++) {
      const node = (this.data.nodeList as NodeObj[])[i]
      if (node.id === data.nodeId) {
        node.left = data.left
        node.top = data.top
      }
    }
  }

  private dbClickNode (evt) {
    // const obj = document.getElementById(evt.id)
    // this.jsPlumb.addToDragSelection(obj)
    this.currentNode = evt
    this.isShowDrawer = true
  }

  private nodeClick (evt) {
    // this.activeElement.type = 'node'
    // this.activeElement.nodeId = evt.id
  }

  private hasLine (from, to) {
    for (let i = 0; i < (this.data.lineList as LineListObj[]).length; i++) {
      const line = (this.data.lineList as LineListObj[])[i]
      if (line.from === from && line.to === to) {
        return true
      }
    }
    return false
  }

  private hasLineFrom (from) {
    for (let i = 0; i < (this.data.lineList as LineListObj[]).length; i++) {
      const line = (this.data.lineList as LineListObj[])[i]
      if (line.from === from) {
        return true
      }
    }
    return false
  }

  // 是否含有相反的线
  private hashOppositeLine (from, to) {
    return this.hasLine(to, from)
  }

  private isSingleOutletNode (type) {
    if (type === 'start') {
      return true
    } else if (type === 'im-node-play') {
      return false
    } else if (type === 'im-node-date') {
      return false
    } else if (type === 'im-node-menu') {
      return false
    } else if (type === 'im-node-transfer') {
      return false
    } else {
      return false
    }
  }

  private getDefaultConditionList (type, id, Label) {
    let conditionList
    switch (type) {
      case 'im-node-transfer':
        conditionList = [
          { label: '排队超时' },
          { label: '排队超量' },
          { label: '无效' }
        ]
        if (type.isShowCancelQueue) {
          conditionList = [
            { label: '排队超时' },
            { label: '排队超量' },
            { label: '无效' },
            { label: '退出排队' }
          ]
        }
        break;
      case 'im-node-date':
        conditionList = [
          {
            label: '默认',
            value: 'default'
          }
        ]
        break;
      case 'im-node-robot':
        conditionList = [
          {
            label: '默认',
            value: 'default'
          }
        ]
        break;
      case 'im-node-branch':
        conditionList = [
          {
            label: '分支1',
            value: '',
            customValue: [{ branchCondiArr: [{ parameterType: 'custom', parameter: '', conditions: 'eq', value: '' }] }]
          },
          {
            label: '其他',
            value: 'default'
          }
        ]
        break;
      default:
        conditionList = [{ label: Label, to: '', value: '' }]
    }
    return conditionList
  }

  private getDefaultConditionLabel (type) {
    let label
    switch (type) {
      case 'startNode':
        label = '下一步'
        break;
      case 'im-node-menu':
        label = '分支1'
        break;
      default:
        label = '条件1'
    }
    return label
  }

  // 删除连线
  private deleteLine (from, to) {
    this.data.lineList = (this.data.lineList as LineListObj[]).filter((line) => {
      if (line.from === from && line.to === to) {
        return false
      }
      return true
    })
  }

  private nodeEditSave (condition, newNodeList, originalConditionLength) {
    this.$nextTick(() => {
      const nodeId = condition[0].id.split('-')[0]
      if (this.savedNodeList.indexOf(nodeId) > -1) {
        this.savedNodeList.splice(this.savedNodeList.indexOf(nodeId), 1)
      }
      const allConnections = cloneDeep(this.jsPlumb.getAllConnections())
      allConnections.forEach((con, conIndex) => {
        if (con.sourceId.split('-')[0] === nodeId) {
          this.jsPlumb.deleteConnectionsForElement(con.sourceId)
          // this.jsPlumb.remove(con.sourceId)
          // try {
          //   this.jsPlumb.deleteConnection(allConnections[conIndex])
          //   this.jsPlumb.unmakeSource(con.sourceId)
          // } catch (error) {
          //   console.log(error)
          // }
        }
      })
      if (originalConditionLength > condition.length) {
        const removeNum = originalConditionLength - condition.length
        for (let i = 1; i < (removeNum + 1); i++) {
          this.jsPlumb.remove(nodeId + '-' + (originalConditionLength - i))
        }
      }
      // 重置ivr导航数据
      (this.data.nodeList as NodeObj[]) = newNodeList
      this.$nextTick(() => {
        condition.forEach((item, index) => {
          // this.jsPlumb.unmakeSource(item.id)
          if (!this.jsPlumb.isSource(item.id)) {
            this.jsPlumb.makeSource(item.id, this.jsplumbSourceOptions)
          }
          if (item.to) {
            this.jsPlumb.connect({ source: item.id, target: item.to }, this.jsplumbConnectOptions)
          }
        })
      })
    })
    this.isShowDrawer = false
  }

  private nodeEditCancel () {
    this.currentNode = {}
    this.isShowDrawer = false
  }

  private ivrSaveClick (ivrForm) {
    if (this.checkIsolated()) {
      this.$message.error('流程中存在孤立节点，无法保存!')
      return false
    }
    if (this.checkNodeRequired()) {
      return false
    }
    let type = 'create'
    if (this.data._id) {
      type = 'update'
    }
    const data = { url: '/im-center/action/config/processConfig/' + type, method: 'POST', data: { ...this.data, ...ivrForm } }
    IvrModule.IvrCommonAction(data).then((res: any) => {
      if (res.success) {
        this.$message.success('保存成功!')
        if (!this.data._id) {
          this.$addOneCache('processList', res.data, true)
        } else {
          this.$updateCache('processList', { ...this.data, ...ivrForm }, '_id', true)
        }
        this.$emit('ivrSaveSuccess', type)
      }
    })
  }

  // 校验孤立节点
  private checkIsolated () {
    let isSolated = false;
    (this.data.nodeList as NodeObj[]).some((item) => {
      let isFrom = false
      let isTo = false
      if ((this.data.lineList as LineListObj[]) && (this.data.lineList as LineListObj[]).length > 0) {
        (this.data.lineList as LineListObj[]).some((lineItem) => {
          if (item.id === lineItem.to) {
            isTo = true
          }
          if (item.id === lineItem.from.split('-')[0]) {
            isFrom = true
          }
          if (item.id === 'startNode') {
            return isTo
          } else {
            return isTo && isFrom
          }
        })
        if (!isTo) {
          if (item.id !== 'startNode') {
            isSolated = true
          }
        }
        return isSolated
      } else {
        isSolated = true
        return false
      }
    })
    return isSolated
  }

  // 校验节点必填项
  private checkNodeRequired () {
    let astrict = false;
    (this.data.nodeList as NodeObj[]).some((item) => {
      if (item.type === 'im-node-start') {
        return false
      } else {
        if (this.savedNodeList.indexOf(item.id) > -1) {
          astrict = true
          this.dbClickNode(item);
          this.$nextTick(() => {
            (this.$refs as any)[item.id].validateForm()
          })
          return true
        }
      }
    })
    return astrict
  }

  private deleteNode (evt) {
    const nodeId = evt.id
    this.$confirm('确定要删除' + evt.name + '节点?', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
      closeOnClickModal: false
    }).then(() => {
      /**
       * 这里需要进行业务判断，是否可以删除
       */
      if (this.isShowDrawer) {
        this.isShowDrawer = false
      }
      const nodeNextList: any = [];
      (this.data as IvrData).nodeList = (this.data.nodeList as NodeObj[]).filter((node) => {
        if (node.id === nodeId) {
          nodeNextList.push(nodeId)
          if (node.condition && node.condition.length > 0) {
            nodeNextList.push(nodeId)
            node.condition.forEach((item, index) => {
              nodeNextList.push(nodeId + '-' + index)
            })
          }
          return false
        }
        return true
      })
      this.$nextTick(() => {
        nodeNextList.forEach(element => {
          this.jsPlumb.removeAllEndpoints(element)
        })
      })
    })
    return true
  }

  private getUUID () {
    return uuidv4().replace(/-/g, '')
  }

  private keyBoardClick () {
    if (this.activeElement.type === 'line') {
      this.$confirm('确定删除所点击的线吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        const conn = this.jsPlumb.getConnections({
          source: this.activeElement.sourceId,
          target: this.activeElement.targetId
        })[0]
        this.jsPlumb.deleteConnection(conn)
        this.activeElement = {
          type: '',
          sourceId: '',
          targetId: ''
        }
      })
    }
  }
}

</script>

<style lang="stylus" scoped>
.ef-dot
  background red
*:focus
  outline none
.workflow
  width 100%
  height 100%
  background #F3F5F7
  border-radius 10px
  box-shadow 0px 0px 4px 0px #E0E6F0, 0px 1px 4px 0px #E0E6F0
  border-radius 10px
.drag-box
  position relative
  display flex
.drag-ul
  margin 0
  padding 0
  width 100px
  background #f7f9fb
.drop
  position relative
  width 100%
  height 100%
  overflow hidden
  outline none !important
  // background-image: linear-gradient(#eee 1px, transparent 0), linear-gradient(90deg, #eee 1px, transparent 0), linear-gradient(#f5f5f5 1px, transparent 0), linear-gradient(90deg, #f5f5f5 1px, transparent 0);
  // background-size: 75px 75px, 75px 75px, 15px 15px, 15px 15px;
  background-image -webkit-radial-gradient(#E0E6F0 2px, rgba(0, 0, 0, 0) 2px)
  background-image radial-gradient(#E0E6F0 2px, rgba(0, 0, 0, 0) 2px)
  background-size 20px 20px
.drop .canvas
  position relative
  height 10000px
  width 10000px
  outline none !important
  top 0px
  left 0px
.node
  position absolute
  width 120px
  padding 0 5px
  border-width 2px
  border 1px solid #409eff
  border-radius 5px
.right-menu
  position fixed
  left 9999px
  top 9999px
  z-index 100
  padding 0
  margin 0
  background #fff
.right-menu li
  list-style none
  padding 0 10px
  height 30px
  line-height 30px
  font-size 12px
  cursor pointer
.node-name
  max-width 75px
.select-node
  background #00c88d
  color #fff
.connectorHoverClass path
  stroke #00c88d
.node-log
  height 100%
  width 100%
.side-content
  height 100%
  width 100%
.toolbar
  border-bottom none
  height 50px
  line-height 50px
.drag-item
  margin-bottom 10px
  cursor move
  color rgb(27, 28, 35)
  border 1px solid #409eff
  border-radius 5px
  text-align center
  list-style none
.drag-box
  height 100%
  width 100%
.text-align-right
  text-align right
.cursor-crosshair
  cursor crosshair
.btns
  margin-top 20px
  text-align center
.btn-box
  padding 10px
</style>
<style lang='stylus'>
.im-edit-drawer
  .el-drawer__header
    height 50px
    padding 0 20px 0
  .el-drawer__body
    flex none
    height calc(100% - 50px)
    .el-form-item--mini
      margin-bottom 23px
</style>
